extends FiniteState


class_name FiniteStateMachine
"""
状态机组件
"""


## 状态切换
signal event_state_changed(state_machine: FiniteStateMachine, from: FiniteState, to: FiniteState, duration: float)


## 初始化状态
@export var init_state: FiniteState = null
## 挂载的状态
@export var finite_states: Array[FiniteState] = []


## 所有状态
var __states: Dictionary = {}
## 当前状态
var __current_state: FiniteState = null
## 下一个待切换的状态
var __next_state_queue: Array[FiniteState] = []
## 当前状态持续时间
var __current_state_duration: float = 0


func __check_exports() -> Dictionary:
    return IComponent.merge({
        "init_state": IComponent.find_child.bind(self, func(x): return x is FiniteState, init_state),
        "finite_states": [IComponent.find_children.bind(self, func(x): return x is FiniteState, finite_states)],
    }, super.__check_exports())

func __prepare() -> void:
    super.__prepare()
    for c in finite_states:
        if c is FiniteState:
            __states[c.name] = c
    __current_state = init_state

func enter() -> void:
    super.enter()
    if __current_state:
        __current_state.enter()

func exit() -> void:
    if __current_state:
        __current_state.exit()
    super.exit()

func switch_to(next: FiniteState) -> bool:
    if __current_state == next:
        return false
    __next_state_queue.push_back(next)
    return true

func switch_to_next(next: FiniteState) -> void:
    if __current_state:
        __current_state.exit()
    event_state_changed.emit(self, __current_state, next, __current_state_duration)
    __current_state = next
    __current_state.enter()
    __current_state_duration = 0

func switch(to_state_name: String) -> bool:
    var next: FiniteState = __states.get(to_state_name)
    if next == null:
        printerr("state is null:%s [%s]" % [to_state_name, __states.keys()])
        return false
    return switch_to(next)

func update(delta: float) -> void:
    if __current_state:
        __current_state_duration += delta
        __current_state.update(delta)
    if __next_state_queue.size() > 0:
        switch_to_next(__next_state_queue.pop_front())
    super.update(delta)
